﻿/*
 * Authors:
 *   钟峰(Popeye Zhong) <9555843@qq.com>
 *
 * Copyright (c) 2017 Flagwind Game Studio. All rights reserved.
 */

using System;
using System.Collections.Generic;

namespace Flagwind.Gaming.Triplets
{
	/// <summary>
	/// 表示“诈金花”牌手的分数评估器类。
	/// </summary>
	public class TripletEvaluator : IGameEvaluator
	{
		#region 单例字段
		public static readonly TripletEvaluator Default = new TripletEvaluator();
		#endregion

		#region 公共方法
		public byte GetRank(byte value)
		{
			var rand = Poker.GetRank(value);

			if(rand == 0)
				return 0;

			if(rand == 1)
				return 13;
			else
				return (byte)(rand - 1);
		}

		public int Evaluate(ArraySegment<byte> values)
		{
			//定义特殊牌型的计分权重
			const int WEIGHT = 14 * 14 * 14;

			//如果指定牌数不为3则表示无效的牌（返回零）
			if(values.Count != 3)
				return 0;

			var score = 0;       //总计得分值
			var ranks = 0;       //同牌计算器（1:对子，2:豹子）
			var suits = 0;       //花色计数器
			var straights = 0;   //顺子计数器

			//将指定一手牌进行排序
			var cards = this.Sort(values);

			for(int i = 0; i < cards.Length; i++)
			{
				//卡牌点数为零则表示该手牌无效
				if(cards[i].Rank == 0)
					return 0;

				if(i > 0)
				{
					if(cards[i].Suit == cards[i - 1].Suit)
						suits++;

					if(cards[i].Rank == cards[i - 1].Rank)
						ranks++;

					if(cards[i].Rank == cards[i - 1].Rank + 1)
						straights++;
				}

				score += cards[i].Rank * (int)Math.Pow(14, i);
			}

			//如果有同牌则直接返回
			if(ranks > 0)
			{
				if(ranks == 1)  //对子
					return score + WEIGHT;
				else            //豹子
					return score + WEIGHT * 9;
			}

			//附加分数值
			var extra = 0;

			if(suits > 1) //同花
				extra += WEIGHT * 3;

			if(straights > 1) //顺子
				extra += WEIGHT * 2;

			return score + extra;
		}
		#endregion

		#region 私有方法
		private Poker[] Sort(ArraySegment<byte> values)
		{
			var pokers = new Poker[values.Count];

			for(var i = 0; i < values.Count; i++)
			{
				var value = values.Array[values.Offset + i];
				pokers[i] = new Poker(value, this.GetRank(value));

				for(var j = i - 1; j >= 0; j--)
				{
					if(pokers[j].Rank <= pokers[j + 1].Rank)
						break;

					var temp = pokers[j + 1];
					pokers[j + 1] = pokers[j];
					pokers[j] = temp;
				}
			}

			return pokers;
		}
		#endregion
	}
}
